package com.yuanian.ecsplus.template;

import com.yuanian.ecsplus.annotation.controller.ControllerResult;
import com.yuanian.ecsplus.bean.CommonModel;
import com.yuanian.ecsplus.bean.entity.SimpleDataModel;
import com.yuanian.ecsplus.bean.vo.FullDataModel;
import com.yuanian.ecsplus.bean.vo.PageModel;
import com.yuanian.ecsplus.enums.OperateType;
import com.yuanian.ecsplus.enums.QueryMode;
import com.yuanian.ecsplus.model.entity.BaseModel;
import com.yuanian.ecsplus.model.vo.BaseVoModel;
import com.yuanian.ecsplus.page.PageFilter;
import com.yuanian.ecsplus.page.PageSql;
import com.yuanian.ecsplus.page.Pagination;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * controller的基类,继承此类拥有下面的通用方法
 * @param <T>
 */
public abstract class ControllerTemplate<T extends BaseModel> extends BaseTemplate {

    @PostMapping("/create")
    @Transactional
    @ControllerResult(operateType = OperateType.CREATE)
    public T create(@RequestParam(value = "insertFlag", required = false, defaultValue = "false") Boolean insertFlag) {
        Class clz = getClazz();
        SimpleDataModel<T> fullDataModel = new SimpleDataModel<>(clz);
        Map initData = new HashMap();
        createBeforeCallback(initData, insertFlag);
        T t = fullDataModel.createOne(initData, insertFlag);
        createAfterCallback(t, insertFlag);
        return t;
    }

    protected abstract void createBeforeCallback(Map initData, Boolean insertFlag);

    protected abstract void createAfterCallback(T t, Boolean insertFlag);

    @PostMapping("/insert")
    @Transactional
    @ControllerResult(operateType = OperateType.INSERT)
    public void insert(@RequestBody T t) {
        if (insertBeforeCallback(t)) {
            t.insert();
            insertAfterCallback(t);
        }
    }

    protected abstract boolean insertBeforeCallback(T t);

    protected abstract void insertAfterCallback(T t);

    @PostMapping("/save")
    @Transactional
    @ControllerResult(operateType = OperateType.SAVE)
    public void save(@RequestBody T t) {
        if (saveBeforeCallback(t)) {
            t.save();
            saveAfterCallback(t);
        }
    }

    protected abstract boolean saveBeforeCallback(T t);

    protected abstract void saveAfterCallback(T t);

    @PostMapping("/update")
    @Transactional
    @ControllerResult(operateType = OperateType.UPDATE)
    public void update(@RequestBody T t) {
        if (updateBeforeCallback(t)) {
            t.update();
            updateAfterCallback(t);
        }
    }

    protected abstract boolean updateBeforeCallback(T t);

    protected abstract void updateAfterCallback(T t);

    @PostMapping("/delete")
    @Transactional
    @ControllerResult(operateType = OperateType.DELETE)
    public void delete(@RequestBody T t) {
        if (deleteBeforeCallback(t)) {
            t.delete();
            deleteAfterCallback(t);
        }
    }

    protected abstract boolean deleteBeforeCallback(T t);

    protected abstract void deleteAfterCallback(T t);

    @PostMapping("/deleteByObjectId")
    @Transactional
    @ControllerResult(operateType = OperateType.DELETE)
    public void deleteByObjectId(@RequestParam String objectId) {
        if (deleteByObjectIdBeforeCallback(objectId)) {
            Class clz = getClazz();
            CommonModel<T> commonModel = new CommonModel<>(clz);
            commonModel.deleteByObjectId(objectId);
            deleteByObjectIdAfterCallback(objectId);
        }
    }

    protected abstract boolean deleteByObjectIdBeforeCallback(String objectId);

    protected abstract void deleteByObjectIdAfterCallback(String objectId);

    @PostMapping("/issue")
    @Transactional
    @ControllerResult(operateType = OperateType.ISSUE)
    public void issue(@RequestBody T t) {
        if (issueBeforeCallback(t)) {
            t.issue();
            issueAfterCallback(t);
        }
    }

    protected abstract boolean issueBeforeCallback(T t);

    protected abstract void issueAfterCallback(T t);

    @PostMapping("/selectByObjectId")
    @Transactional(readOnly = true)
    @ControllerResult(operateType = OperateType.QUERY)
    public T selectByObjectId(@RequestParam String objectId, @RequestParam(value = "viewFlag", required = false, defaultValue = "false") Boolean viewFlag) {
        selectByObjectIdBeforeCallback(objectId, viewFlag);
        Class clz = getClazz();
        CommonModel<T> fullDataModel = new CommonModel<>(clz);
        T t = fullDataModel.selectByObjectId(objectId);
        selectByObjectIdAfterCallback(t, viewFlag);
        return t;
    }

    protected abstract void selectByObjectIdBeforeCallback(String objectId, Boolean viewFlag);

    protected abstract void selectByObjectIdAfterCallback(T t, Boolean viewFlag);

    @PostMapping("/page")
    @Transactional(readOnly = true)
    @ControllerResult(operateType = OperateType.QUERY)
    public Pagination<T> page(@RequestBody PageSql pageSql) {
        pageSelectListBeforeCallback(pageSql);
        Class clz = getClazz();
        PageModel<T> pageModel = new PageModel<>(clz);
        QueryMode.setMode(QueryMode.HUMP);
        if (pageSql.getOrderBy() == null || pageSql.getOrderBy().trim().length() == 0) {
            pageSql.setOrderBy("createDate");
        }
        Pagination<T> tPagination = pageModel.selectList(pageSql.getSql(), pageSql.getLimit(), pageSql.getOffset(), pageSql.getOrderBy());
        pageSelectListAfterCallback(tPagination);
        return tPagination;
    }

    /**
     * 根据params生成sql
     * @return
     */
    protected abstract void pageSelectListBeforeCallback(PageSql pageSql);

    /**
     * 根据params生成sql
     * @return
     */
    protected abstract void pageSelectListAfterCallback(Pagination<T> tPagination);

    @PostMapping("/pageFilter")
    @Transactional(readOnly = true)
    @ControllerResult(operateType = OperateType.QUERY)
    public Pagination<T> pageFilter(@RequestBody PageFilter pageFilter) {
        Class clz = getClazz();
        PageModel<T> pageModel = new PageModel<>(clz);
        QueryMode.setMode(QueryMode.HUMP);
        Pagination<T> tPagination = pageModel.selectList(pageFilterSelectListBeforeCallback(clz, pageFilter), pageFilter.getLimit(), pageFilter.getOffset(), "createDate");
        pageFilterSelectListAfterCallback(tPagination);
        return tPagination;
    }

    /**
     * 根据params生成sql
     * @return
     */
    protected abstract String pageFilterSelectListBeforeCallback(Class clz, PageFilter pageFilter);

    /**
     * 根据params生成sql
     * @return
     */
    protected abstract void pageFilterSelectListAfterCallback(Pagination<T> tPagination);

    @PostMapping("/batchSave")
    @Transactional
    @ControllerResult(operateType = OperateType.SAVE)
    public void batchSave(@RequestBody List<T> list) {
        if (batchSaveBeforeCallback(list)) {
            Class clz = getClazz();
            CommonModel<T> fullDataModel = new CommonModel<>(clz);
            fullDataModel.batchSave(list);
            batchSaveAfterCallback(list);
        }
    }

    protected abstract boolean batchSaveBeforeCallback(List<T> list);

    protected abstract void batchSaveAfterCallback(List<T> list);

    @PostMapping("/batchInsert")
    @Transactional
    @ControllerResult(operateType = OperateType.INSERT)
    public List<T> batchInsert(@RequestBody List<T> list) {
        if (batchInsertBeforeCallback(list)) {
            Class clz = getClazz();
            CommonModel<T> fullDataModel = new CommonModel<>(clz);
            fullDataModel.batchInsert(list);
            batchInsertAfterCallback(list);
            return list;
        }
        return null;
    }

    protected abstract boolean batchInsertBeforeCallback(List<T> list);

    protected abstract void batchInsertAfterCallback(List<T> list);

    @PostMapping("/batchDelete")
    @Transactional
    @ControllerResult(operateType = OperateType.INSERT)
    public Integer batchDelete(@RequestBody List<T> list) {
        if (batchDeleteBeforeCallback(list)) {
            Class clz = getClazz();
            CommonModel<T> fullDataModel = new CommonModel<>(clz);
            int num = fullDataModel.batchDelete(list);
            batchDeleteAfterCallback(list);
            return num;
        }
        return null;
    }

    protected abstract boolean batchDeleteBeforeCallback(List<T> list);

    protected abstract void batchDeleteAfterCallback(List<T> list);

}
